// server main.c
#include "threadPool.h"
#include "taskQueue.h"
#define MAX_CLIENTS 1024
static user_t* clients[MAX_CLIENTS] = {NULL};
static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;

int exitPipe[2];
// 客户端断开时的清理函数
void _client_cleanup(int cfd) {
    pthread_mutex_lock(&clients_mutex);
    user_t* user = clients[cfd];
    if (user) {
        // 释放目录栈内存
        while (!_dirStack_empty(&user->_dirStack)) {
            _dirStack_pop(&user->_dirStack);
        }
        free(user);
        clients[cfd] = NULL;
    }
    pthread_mutex_unlock(&clients_mutex);
    close(cfd);
    printf("Client %d cleaned up\n", cfd);
}

void handler(int signum){
    printf("signum = %d\n", signum);
    int res = write(exitPipe[1], "1", 1);
    ERROR_CHECK(res, -1, "write");
}

void _clean_pre_space(char* buf) {
    int begin = 0;
    while (buf[begin] == ' ') {
        begin++;
    }
    if (begin > 0) {
        int i = 0;
        while (buf[begin] != '\0') {
            buf[i++] = buf[begin++];
        }
        buf[i] = '\0'; 
    }
}

CmdType _get_client_cmd(char* _data){
    // c++ map
    /* printf("_data = %s\n", _data); */
    char cmd[1024] = { 0 };
    int begin = 0;
    // del pre 0
    while(_data[begin] == ' ' || _data[begin] == '\n' || _data[begin] == '\r'){
        begin++;
    }
    /* printf("_data = %s\n", _data + begin); */
    // get end
    int end = begin;
    while(_data[end] != ' ' && _data[end] != '\0' && _data[end] != '\n' && _data[end] != '\r'){
        end++;
    }    
    memcpy(cmd, _data + begin, end - begin);
    cmd[end - begin] = '\0';
    /* printf("cmd = %s\n", cmd); */
    // delete cmd & move args 
    int arg_begin = end;
    // 跳过命令后的空格或换行符
    while (_data[arg_begin] == ' ' || _data[arg_begin] == '\n' || _data[arg_begin] == '\r') {
        arg_begin++;
    }
    // 移动参数到_data起始位置
    memmove(_data, _data + arg_begin, strlen(_data + arg_begin) + 1); // +1包含结束符
    _clean_pre_space(_data); 
    
    // return CMD_TYPE_cmd
    if(strcmp(cmd, "cd") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_CD;
    } else if(strcmp(cmd, "ls") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_LS;
    } else if(strcmp(cmd, "pwd") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_PWD;
    } else if(strcmp(cmd, "mkdir") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_MKDIR;
    } else if(strcmp(cmd, "rmdir") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_RMDIR;
    } else if(strcmp(cmd, "remove") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_REMOVE;
    } else if(strcmp(cmd, "puts") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_PUTS;
    } else if(strcmp(cmd, "gets") == 0){
        _clean_pre_space(_data);
        return CMD_TYPE_GETS;
    } else{
        // 不是命令 可能是文件 不清楚前导空格
        return CMD_TYPE_INIT;
    }
}


int main(int argc,char* args[])
{
    ARGS_CHECK(argc, 4);
    pipe(exitPipe);
    if(fork()){
        close(exitPipe[0]);
        signal(SIGUSR1, handler);// SIGUSR1 = 10
        wait(NULL);
        exit(0);
    }

    printf("server proccess start.\n");

    close(exitPipe[1]);

    int sockfd = tcp_init(args[1], args[2]);

    threadPool_t pool;
    threadPool_init(&pool, atoi(args[3]));

    int epfd = epoll_create(1);
    epollAdd(epfd, sockfd);
    epollAdd(epfd, exitPipe[0]);

    char buf[4096] = { 0 };
    int netfd = -1;
    struct epoll_event readySet[1024];
    while(1){
        int readyNum = epoll_wait(epfd, readySet, 1024, -1);
        for(int i = 0;i < readyNum; ++i){
            int cfd = readySet[i].data.fd;
            if(cfd == sockfd){
                netfd = accept(sockfd, NULL, NULL);
                printf("new connect netfd = %d\n", netfd);
                epollAdd(epfd ,netfd);

                // make user
                user_t* user = (user_t*)malloc(sizeof(user_t));
                user_init(user);
                user->_clientFd = netfd;

                pthread_mutex_lock(&pool._mutex);
                if(netfd < MAX_CLIENTS) clients[netfd] = user;
                pthread_mutex_unlock(&pool._mutex);

            }else if(cfd == exitPipe[0]){
                printf("get SIGUSR1\n");
                pthread_mutex_lock(&pool._mutex);
                pool._exitFlag = 1;
                pthread_cond_broadcast(&pool._cond);
                pthread_mutex_unlock(&pool._mutex);
                for(int i = 0;i < pool._tidArr._worker_num; ++i){
                    pthread_join(pool._tidArr._arr[i], NULL);
                    printf("worker %d exit.\n", i);
                }
                printf("subprocess exit.\n");
                exit(0);
            }
            // clientFd
            else if(cfd != -1){
                /* printf("clientfd = %d\n", cfd); */
                ssize_t sret = recv(cfd, buf, sizeof(buf), 0);
                if(sret <= 0){ // 客户端断开
                    printf("Client %d disconnected\n", cfd);
                    epollDel(epfd, cfd);
                    _client_cleanup(cfd);
                    continue;
                }
                buf[sret] = '\0';
                /* printf("buf = %s\n", buf); */

              

                // make task_t

                task_t* task = (task_t*)malloc(sizeof(task_t));
                _task_init(task);
                strcpy(task->_data, buf);
                task->_cmdType = _get_client_cmd(task->_data);
                task->_clientFd = cfd;
                /* printf("task->_data = %s\n", task->_data);// cout all string in task->_data */
                
                // make user
                pthread_mutex_lock(&pool._mutex);
                if(netfd < MAX_CLIENTS){
                    task->_user = clients[cfd];
                }

                pthread_mutex_unlock(&pool._mutex);
                _taskQueue_enque(&pool._q, task);
                pthread_cond_broadcast(&pool._cond);
                pthread_mutex_unlock(&pool._mutex);

            }        
        }
    }

}

